package lk.icta.core.service.impl;

import lk.icta.common.ELandRuntimeException;
import lk.icta.common.ErrorCodes;
import lk.icta.common.service.MailSenderService;
import lk.icta.common.util.MailUtil;
import lk.icta.core.dao.ScheduleDAO;
import lk.icta.core.entity.Schedule;
import lk.icta.core.service.ScheduleManagementService;
import lk.icta.user.common.Permission;
import lk.icta.user.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author Duminda Dharmakeerthi
 */
public class ScheduleManagementServiceImpl implements ScheduleManagementService {

    private static final Logger logger = LoggerFactory.getLogger(ScheduleManagementServiceImpl.class);
    private final ScheduleDAO scheduleDAO;
    private final MailSenderService mailSenderService;

    public ScheduleManagementServiceImpl(ScheduleDAO scheduleDAO, MailSenderService mailSenderService) {
        this.scheduleDAO = scheduleDAO;
        this.mailSenderService = mailSenderService;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addSchedule(Schedule schedule, User user) {
        logger.debug("Adding a Schedule {}", schedule.getId());
        if (!user.isAuthorized(Permission.LAND_VISIT_SCHEDULE)) {
            handleELandRuntimeException(user.getUsername() + " doesn't have permission to add a schedule", ErrorCodes.UNAUTHORIZED_ACCESS);
        } else {
            scheduleDAO.addSchedule(schedule, user);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateSchedule(Schedule schedule, User user) {
        logger.debug("Updating a Schedule {}", schedule.getId());
        if (!user.isAuthorized(Permission.LAND_VISIT_SCHEDULE)) {
            handleELandRuntimeException(user.getUsername() + " doesn't have permission to update a schedule", ErrorCodes.UNAUTHORIZED_ACCESS);
        } else {
            scheduleDAO.updateSchedule(schedule, user);
        }
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public void triggerScheduledJobs() {
        logger.info("Start executing scheduled tasks..");
        Date date = new Date();
        List<Schedule> scheduleList = scheduleDAO.getAllActiveSchedule(Schedule.Status.ACTIVE);

        if (scheduleList != null) {
            for (Schedule schedule : scheduleList) {
                if (date.after(schedule.getStartDate()) && date.before(schedule.getEndDate())) {
                    mailSenderService.sendMail("from@no-spam.com", schedule.getLifeCycleInfo().getCreatedUser().getEmail(),
                            "eSlims - Land Visit Reminder", "You have scheduled lands to be visited before " +
                                    schedule.getEndDate());

                }
            }
        }
        logger.info("Stopped executing scheduled tasks..");
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<Schedule> getAllActiveSchedule(Schedule.Status status) {
        List<Schedule> scheduleList = scheduleDAO.getAllActiveSchedule(status);
        if (scheduleList != null && scheduleList.size() > 0) {
            return scheduleList;
        }
        return Collections.emptyList();
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<Schedule> getAllActiveSchedulesByDSDivision(Schedule.Status status, int dsDivisionId, User user) {
        logger.debug("Listing active schedules of D.S. Division {} by {}", dsDivisionId, user.getUsername());
        List<Schedule> scheduleList = scheduleDAO.getAllActiveSchedulesByDSDivision(status, dsDivisionId);
        if (scheduleList != null && scheduleList.size() > 0) {
            return scheduleList;
        }
        return Collections.emptyList();
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public Schedule getScheduleById(int id) {
        return scheduleDAO.getScheduleById(id);
    }

    private void handleELandRuntimeException(String message, int code) {
        logger.error(message);
        throw new ELandRuntimeException(message, code);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<Schedule> getScheduleByDate(Date startDate) {
        List<Schedule> scheduleList = scheduleDAO.getScheduleByDate(startDate);
        if (scheduleList != null && scheduleList.size() > 0) {
            return scheduleList;
        }
        return Collections.emptyList();
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<Schedule> getScheduleByLandId(long landId, User user) {
        List<Schedule> scheduleList = scheduleDAO.getScheduleByLandId(landId);
        if (scheduleList != null && scheduleList.size() > 0) {
            return scheduleList;
        }
        return Collections.emptyList();
    }
}
